/**
 * @file task_pcb.c
 * @brief 
 * @author Tome (zigbee86@163.com)
 * @date 2021-01-05
 */
 

#include "OSAL.h" 
#include "osal_log.h"

#include "hal_led.h"
#include "hal_key.h"
#include "hal_host.h"
#include "hal_cw2017.h"
#include "hal_wdt.h"
#include "hal_sy6982.h"
#include "hal_sy6982_port.h"

#include "stdio.h"

#include "task_pcb.h"
#include "task_time.h"
#include "task_led.h"

#include "onboard.h"

 
#if BOARD_ERRCHK_ENABLE 
 
/****************************************************************************************************************************** 
                                                            const
*******************************************************************************************************************************/












/****************************************************************************************************************************** 
                                                            typedef
*******************************************************************************************************************************/










/****************************************************************************************************************************** 
                                                            MICRO
*******************************************************************************************************************************/


#define TASK_TEST_ENTRY                     PCB_task_num //10
#define TASK_TEST_SEND_MSG_INTERNAL_MIN     10 //ms


#define HAL_WDT_FEET()      HalWdtFeedDog()

/****************************************************************************************************************************** 
                                                            declearation
*******************************************************************************************************************************/



static void task_pcb_ProcessOSALMsg(osal_event_hdr_t *pMsg );
static void log_menu_handler(uint8* str, uint16 len);
static void task_pcb_sy6982_led_poll(void);

void pcb_gpio_init(void);

/****************************************************************************************************************************** 
                                                            defination
*******************************************************************************************************************************/



static uint8 PCB_TaskID;


static uint8 PCB_task_min = 0xff, PCB_task_max;

/**************************************************************************************************
 * @fn      Hal_Init
 *
 * @brief   Hal Initialization function.
 *
 * @param   task_id - Hal TaskId
 *
 * @return  None
 **************************************************************************************************/
void PCB_Init( uint8 task_id )
{
    
  static uint8 init = FALSE;    
  /* Register task ID */
  PCB_TaskID = task_id;
    
  UNUSED_VARIABLE(PCB_TaskID);
    
    
  if ( init == FALSE )
  {
      
      PCB_task_min = task_id;
      pcb_gpio_init();
      
//     osal_start_reload_timer(task_id, TASK_TEST_EVT_1S, 1000 );
//     osal_start_timerEx(task_id, TASK_TEST_EVT_RDMSEND, 500 );
//     HalLedBlink(HAL_LED_4, 10, 50, 1000);
//      
      
  //  osal_start_timerEx(task_id, TASK_TEST_EVT_PM, 300);
    osal_pwrmgr_task_state( task_id, PWRMGR_HOLD);
      
    osal_log_register(task_id);
      
   //   osal_start_reload_timer(PCB_TaskID,  TASK_PCB_EVT_CHG_POLL, 3);
      
      osal_start_reload_timer(PCB_TaskID,  TASK_PCB_EVT_GPIO_CHK, 1000);
      
    init = TRUE;
  }
    
  LOG("PCB task %d start", task_id);
  
  if ( PCB_task_min > task_id )PCB_task_min = task_id;
  
  if ( PCB_task_max < task_id )PCB_task_max = task_id;
}



void pcb_gpio_init(void)
{
//    M0P_GPIO->P14_SEL_f.SEL = 0;
//    M0P_GPIO->P15_SEL_f.SEL = 0;
//    
//    #define TEST_PIN_DIR    GpioDirIn
//    #define TEST_PULLUP     TRUE
//    #define TEST_PULLDOWN   FALSE
//    #define TEST_OD         FALSE
//    #define TEST_DRYLOW     TRUE
//     
//    Gpio_InitIOExt(1, 4, TEST_PIN_DIR, TEST_PULLUP, TEST_PULLDOWN, TEST_OD, TEST_DRYLOW); 
//    Gpio_InitIOExt(1, 5, TEST_PIN_DIR, TEST_PULLUP, TEST_PULLDOWN, TEST_OD, TEST_DRYLOW); 
//    Gpio_InitIOExt(2, 3, TEST_PIN_DIR, TEST_PULLUP, TEST_PULLDOWN, TEST_OD, TEST_DRYLOW); 
//    Gpio_InitIOExt(2, 4, TEST_PIN_DIR, TEST_PULLUP, TEST_PULLDOWN, TEST_OD, TEST_DRYLOW); 
//    
}


void pcb_pgio_toggle(void)
{
//    static uint8 lvl = 0;
//    
//    Gpio_SetIO(1 , 4, lvl);
//    Gpio_SetIO(1 , 5, lvl);
//    Gpio_SetIO(2 , 4, lvl);
//    Gpio_SetIO(2 , 3, lvl);
//    
//    lvl = !lvl;
}



/**************************************************************************************************
 * @fn      PCB_ProcessEvent
 *
 * @brief   PCB Process Event
 *
 * @param   task_id - Hal TaskId
 *          events - events
 *
 * @return  None
 **************************************************************************************************/
uint16 PCB_ProcessEvent( uint8 task_id, uint16 events )
{
  uint8 *msgPtr;
    
  //uint16 rdm = 0;
  //uint8  tar_task;
  
  (void)task_id;  // Intentionally unreferenced parameter

  if ( events & SYS_EVENT_MSG )
  {
        msgPtr = osal_msg_receive(task_id);

        while (msgPtr)
        {
          /* Do something here - for now, just deallocate the msg and move on */
            
          //LOG("T %02d, %s", task_id,msgPtr);
            
           task_pcb_ProcessOSALMsg((osal_event_hdr_t *)msgPtr );     

          /* De-allocate */
          osal_msg_deallocate( msgPtr );
          /* Next */
          msgPtr = osal_msg_receive( task_id );
        }
      return (events ^ SYS_EVENT_MSG );
  }
  
  if ( OSAL_EVENT_MATCH ( TASK_PCB_EVT_CHG_POLL ))
  {
      //task_pcb_sy6982_led_poll();
      OSAL_EVENT_KICK( TASK_PCB_EVT_CHG_POLL );
  }
  
  if ( OSAL_EVENT_MATCH( TASK_PCB_EVT_GPIO_CHK ))
  {
      
      pcb_pgio_toggle();
      
      OSAL_EVENT_KICK( TASK_PCB_EVT_GPIO_CHK );
  }
  

   return 0;
}


/*********************************************************************
 * @fn      funcname
 *
 * @brief   
 *
 * @param   
 *
 *
 * @return  
 */
static void task_pcb_sy6982_led_poll(void)
{
    
    
    uint8 on = SYSTA_PIN_GET();
    
    HalLedSet(HAL_LED_1, on ? HAL_LED_MODE_ON : HAL_LED_MODE_OFF);
}

/*********************************************************************
 * @fn      task_pcb_HandleKeys
 *
 * @brief   Handles all key events for this device.
 *
 * @param   shift - true if in shift/alt.
 * @param   keys  - bit field for key events.
 *
 * @return  none
 */
void task_pcb_HandleKeys( uint8 shift, uint8 keys )
{
   
    UNUSED_VARIABLE(shift);
    
    
    
    if ( keys  & HAL_BTN_DK )
    {
        LOG("key press");
        //test_task_powermode_change();
        tlv_and_tree_test();
    }
    
   // test_pin_toggle();
    

        
    //HalLedBreath(HAL_LED_4, 100, 50, 1000);
    
}


/*
    receive log message from RTT / UART
*/
void task_pcb_HandleLogs( uint8* str, uint16 len )
{
    LOG("input:%s", str);
    log_menu_handler(str, len);
}    

 
/******************************************************************************
* @fn        task_pcb_ProcessOSALMsg
*
* @brief     osal system events handler
*
* @param     
*
* @return    none
*/
static void task_pcb_ProcessOSALMsg(osal_event_hdr_t *pMsg )
{
switch ( pMsg->event )
  {
      
    case OSAL_LOG:
        task_pcb_HandleLogs( ((logEvent_t*)pMsg)->data, ((logEvent_t*)pMsg)->len);
    break;
      
  case UART_EVENT:
    //task_pcb_HandleUarts ( ((osalUartEvt_t*)pMsg)->event );
    
    break;

    
  case KEY_CHANGE:
    task_pcb_HandleKeys(  ((keyChange_t*)pMsg)->state, ((keyChange_t*)pMsg)->keys );
    break;
    
    
  default:
    break;
  }  
}

//----------------------------------------------------------------------------------------------------------------------
// input message handler

static void cmd_wakeup_handler(const uint8* str, uint16 len)
{
    //uint8 cmd[20];
//    int   size = 0;
    uint8 sta = 0;
    const char* s = (const char*)str;
    
    //size = sscanf(s, "wakeup");
    if ( osal_memcmp( "wakeup", s, osal_strlen("wakeup")) == FALSE )return;
    
//    LOG("Size  x %d", size);
    sta = HalHostRead();
    
    LOG("wake up pin is %s", sta?"active":"idle");
}


static void cmd_lowpower_handler(const uint8* str, uint16 len)
{
    int mode,m;
    const char* s = (const char*)str;
    
    m = sscanf(s, "lowpower %d", &mode);
    
    if ( m <= 0) return;
    
    LOG("Powermode -> %s", mode ? "hold":"conserve");
    
    osal_pwrmgr_task_state( PCB_TaskID, mode ? PWRMGR_HOLD : PWRMGR_CONSERVE);    
    
}

static void cmd_led_handler_1(const uint8* str, uint16 len)
{
    char cmd[20];
    uint8 leds, mode, duty, layer;
    uint16 period,cycle;
    int nleds,nduty,nperiod,nlayer, ncycle;
    
    char mc;
    const char* s = (const char*)str;
    int m;
    
    m = sscanf(s, "led %s", cmd);
    
    if ( m <= 0 ) return;
    
    if ( cmd[0] == '?' )
    {
        LOG("led help info...");
        return;
    }
    
    m = sscanf(s, "led %x %c %d %d %d %d", &nleds, &mc, &nduty, &nperiod, &nlayer, &ncycle);
    
    if ( m < 0) return;
    
    if ( mc == 'b' )mode = HAL_LED_MODE_BREATH;
    else if ( mc == 'f' ) mode = HAL_LED_MODE_FLASH;
    else if ( mc == 'o' ) mode = HAL_LED_MODE_ON;
    else mode = HAL_LED_MODE_OFF;
        
    leds = (uint8)nleds;
    duty = (uint8)nduty;
    period = (uint16)nperiod;
    layer = (uint8)nlayer;
    cycle = (uint16)ncycle;
    
    
    layer = 1;
    cycle = 10;
    period = 1000;
    
    LOG("led %x", leds);
    
    task_led_set( layer, leds, mode, duty, period, cycle);
    
    LOG("LED success");
    
}



static void cmd_led_handler(const uint8* str, uint16 len)
{
    static led_bits = 0x01;
    char cmd[20];
    uint8 leds, mode, duty, layer;
    uint16 period,cycle;
    int nleds,nmode,nduty,nperiod,nlayer, ncycle;
    
    char lc,mc;
    const char* s = (const char*)str;
    int m;
    
    m = sscanf(s, "led %c %c", &lc, &mc);
    
    if ( m <= 0 ) return;
    
    
    if ((lc >= '0' ) && ( lc <= '2' ))
        layer = lc - '0';
    else
    {
        LOG("LED failure");
        return;
    }
    
    if ( mc == 'b' ) mode = HAL_LED_MODE_BREATH;
    else if ( mc == 'f' ) mode = HAL_LED_MODE_FLASH;
    else if ( mc == 'o' ) mode = HAL_LED_MODE_ON;
    else if ( mc == 'x' ) mode = HAL_LED_MODE_OFF;
    else
    {
        LOG("mode err");
        return;
    }
    
    LOG("layer %d", layer);
    
    leds = led_bits;
    duty = 50;
    period = 1000;
    //layer = (uint8)nlayer;
    cycle = 10;
    
    task_led_set_cover( layer, leds, mode, duty, period, cycle);
    
    LOG("LED success");
    
    led_bits <<= 1;
    led_bits |= 0x01;
    if (led_bits & 0xF0 ) led_bits = 0x01;
}

static void cmd_sy6982_handler(const uint8* str, uint16 len)
{
    char tar;
    int m;
    
    const char* s = (const char*)str;
    m = sscanf(s, "cw2017 %c", &tar);
    
    if ( m <= 0 )return;
    
    if ( tar == 'o' )
    {
        osal_start_reload_timer(PCB_TaskID,  TASK_PCB_EVT_CHG_POLL, 3);
    }
    else
    {
        osal_stop_timerEx(PCB_TaskID,  TASK_PCB_EVT_CHG_POLL);
    }    
}

static void cmd_cw2017_handler(const uint8* str, uint16 len)
{
    char tar;
    int m;
    uint16 num;
    int16 temp;
    uint8 ret = FAILURE;
    
    const char* s = (const char*)str;
    m = sscanf(s, "cw2017 %c", &tar);
    
    if ( m <= 0 )return;
    
    if ( tar == 's' )
    {
        ret = cw_get_capacity(&num);
        if ( ret == ZSUCCESS ) 
        {
            LOG("SOC %d", num);
        }
    }
    else if ( tar == 'v' )
    {
        ret = cw_get_vol(&num);
        if ( ret == ZSUCCESS ) 
        {
            LOG("MV %d", num);
        }
        
    }
    else if ( tar == 't' )
    {
        ret = cw_get_temp(&temp);
        if ( ret == ZSUCCESS ) 
        {
            LOG("TEMP %d", temp);
        }
        
    }
    else if ( tar == 'r' )
    {
        HAL_WDT_FEET();
        cw2017_restart();

        LOG("restart");

    }
    
    if ( ret != ZSUCCESS )
    {
        WARN("failed %d", ret);
    }
    
}
static uint32_t tlv_pro_attr_callback(uint32_t attr, uint8_t option)
{
    LOG("attr %x", attr);
    return 0;
}


static uint32_t tlv_pro_attr_value_callback(uint32_t attr, uint8_t T, uint16_t L, uint8_t *v, uint8_t option)
{
    LOG("attr %x", attr);
    LOG("T %x, L %d", T, L );
    LOG_DUMP_HEX(v, L);
    return 0;
}


static uint32_t tlv_pro_attr_state_callback(uint32_t attr, uint8_t state, uint8_t option)
{
    LOG("attr %x, state %d", attr, state);
    return 0;
}

static uint32_t tlv_pro_attr_state_value_callback(uint32_t attr, uint8_t state,uint8_t T, uint16_t L, uint8_t *v, uint8_t option)
{
    LOG("attr %x, state %d", attr, state);
    LOG("T %x, L %d", T, L );
    LOG_DUMP_HEX(v, L);
    return 0;
}


static void cmd_code_handler(const uint8* str, uint16 len)
{
    char tar;
    int size;
    uint16 num;
    int16 temp;
    uint8 ret = FAILURE;
    
    uint8_t T;
    uint16_t L;
    uint8_t vbuf[100];
    uint8_t state;
    
    /* code */
    uint16_t total = 100, cost = 0;
    uint8_t buf[100];
    uint8_t *pstart = 0;
    /* decode */
    uint8_t fn, op;
    uint32_t did = 0;
    uint32_t attr;
    
    static uint8_t fn_start = 2; 
    
    
    
    
   
    const char* s = (const char*)str;
    size = sscanf(s, "code %c", &tar);
    fn_start++;
    
//    LOG("SSSSSXXXXXXXXXXXXSSSSSSSSSSSSSSSS %d", fn_start);
//    LOG("SSSSSXXXXXXXXXXXXSSSSSSSSSSSSSSSS %d", fn_start);
//    LOG("SSSSSXXXXXXXXXXXXSSSSSSSSSSSSSSSS %d", fn_start);
//    LOG("SSSSSXXXXXXXXXXXXSSSSSSSSSSSSSSSS %d", fn_start);
//    LOG("SSSSSXXXXXXXXXXXXSSSSSSSSSSSSSSSS %d", fn_start);
    
     #if 1
    do {
        cost += tlv_app_pro_code_head_into_buffer(0x01, fn_start, 0x00, 0,0, buf, total);
        
        if ( tar == 'a' )
        {
            cost += tlv_app_pro_code_attr_into_buffer(0x34, buf, total, cost);
            cost += tlv_app_pro_code_attr_into_buffer(0x35, buf, total, cost);
            cost += tlv_app_pro_code_attr_into_buffer(0x36, buf, total, cost);
            cost += tlv_app_pro_code_attr_into_buffer(0x37, buf, total, cost);
            cost = tlv_app_pro_code_finish(buf, total, cost, &pstart);   
            
            if ( cost == 0 ) break;
            //LOG_DUMP_HEX(pstart, cost);
            
            // decode
            total = cost;
            cost = 0;
            
            cost = tlv_app_pro_decode_head(&did, &fn, &op, pstart, total);
            LOG("did %x, fn %d, op %d", did, fn, op);
            
            pstart += cost;
            total -= cost;
            cost = tlv_app_pro_decode_attr(pstart, total, tlv_pro_attr_callback, 0x00);
            
            total -= cost;
            
            //LOG("decode end %d", total);
            
            
        }
        else if ( tar == 'v' ){
            //cost += tlv_app_pro_code_head_into_buffer(0x01, 0x02, 0x00, 0,0, buf, total);
            T = DT_I16; L = 2; vbuf[0] = fn_start; vbuf[1] = 0xaa;
            cost += tlv_app_pro_code_attr_val_into_buffer( 0x34, T, L, vbuf, buf, total, cost);
            cost += tlv_app_pro_code_attr_val_into_buffer( 0x35, T, L, vbuf, buf, total, cost);
            cost += tlv_app_pro_code_attr_val_into_buffer( 0x36, T, L, vbuf, buf, total, cost);
            cost = tlv_app_pro_code_finish(buf, total, cost, &pstart);   
            
            if ( cost == 0 ) break;
            LOG_DUMP_HEX(pstart, cost);
            
            // decode
            total = cost;
            cost = 0;
            
            cost = tlv_app_pro_decode_head(&did, &fn, &op, pstart, total);
            LOG("did %x, fn %d, op %d", did, fn, op);
            
            pstart += cost;
            total -= cost;
            cost = tlv_app_pro_decode_attr_val(pstart, total,vbuf, tlv_pro_attr_value_callback, 0x00);
            
            total -= cost;
            
            //LOG("decode end %d", total);
            
        }
        else if (tar == 's' ) // only state
        {
            state = 0x00;
            
            cost += tlv_app_pro_code_attr_sta_into_buffer( 0x34, state++, buf, total, cost);
            cost += tlv_app_pro_code_attr_sta_into_buffer( 0x35, state++, buf, total, cost);
            cost += tlv_app_pro_code_attr_sta_into_buffer( 0x36, state++, buf, total, cost);
            cost = tlv_app_pro_code_finish(buf, total, cost, &pstart); 
            
            if ( cost == 0 ) break;
            total = cost;
            cost = 0;
            
            cost = tlv_app_pro_decode_head(&did, &fn, &op, pstart, total);
            LOG("did %x, fn %d, op %d", did, fn, op);
            
            pstart += cost;
            total -= cost;
            cost = tlv_app_pro_decode_attr_sta(pstart, total,vbuf, tlv_pro_attr_state_callback, 0x00);
            
            total -= cost;
            
            //LOG("decode end %d", total);            
            
        }
        else if ( tar == 'S' ) // a + s + v
        {
            state = 0x00;
            T = DT_I16; L = 2; vbuf[0] = fn_start; vbuf[1] = 0xaa;
            
            cost += tlv_app_pro_code_attr_sta_val_into_buffer( 0x34, state++, T, L, vbuf, buf, total, cost);
            cost += tlv_app_pro_code_attr_sta_val_into_buffer( 0x35, state++, T, L, vbuf, buf, total, cost);
            cost += tlv_app_pro_code_attr_sta_val_into_buffer( 0x36, state++, T, L, vbuf, buf, total, cost);
            cost = tlv_app_pro_code_finish(buf, total, cost, &pstart);
            
            if ( cost == 0 ) break;
            total = cost;
            cost = 0;
            
            cost = tlv_app_pro_decode_head(&did, &fn, &op, pstart, total);
            LOG("did %x, fn %d, op %d", did, fn, op);
            
            pstart += cost;
            total -= cost;
            
            cost = tlv_app_pro_decode_attr_sta_val(pstart, total, vbuf, tlv_pro_attr_state_value_callback, 0x00);
            
            total -= cost;
            
            
        }
        
        
        if ( cost )
        {
            LOG("decode end %d", total);            
            
        }
        
    }while(0);
    #endif
    
}

static void cmd_reset_handler(const uint8* str, uint16 len)
{
    const char* s = (const char*)str;
    
    //size = sscanf(s, "wakeup");
    if ( osal_memcmp( "reset", s, osal_strlen("reset")) == FALSE )return;
    
    LOG("reset...");
    
    while(1);
}


static void cmd_usb_handler(const uint8* str, uint16 len)
{
    uint8 cmd[10];
    uint8 sta;
    const char* s = (const char*)str;
    
    int m;
    uint16 num;
    int16 temp;
    uint8 ret = FAILURE;
    
    m = sscanf(s, "usb %s", cmd);
    
    LOG("m %d", m);
    
    if ( m < 1 ) goto _ret;
    
    
    if ( osal_memcmp(cmd,"insert",osal_strlen("insert")) == TRUE )
    {
        ret = ZSUCCESS;
        sta = hal_usb_insterd_check();
        LOG("USB is %s", sta ? "IN" : "OUT");
    }
    else  if ( osal_memcmp(cmd,"led",osal_strlen("led")) == TRUE )
    {
        ret = ZSUCCESS;
        sta = SYSTA_PIN_GET();
        LOG("LED is %s", sta ? "ON" : "OFF");
    }
        
    
    _ret:
    
    if ( ret != ZSUCCESS )WARN("failed %d", ret);
    
}


static void log_menu_handler(uint8* str, uint16 len)
{
    uint16 i = 0;
    uint8* dat = str;
    
        //skip space
    for(; i<len; i++) { if( dat[i] != ' ' )break; }
    len -= i;
    str+= i;
    //
    switch (dat[0] )
    {
        case 'H':
        case '?':
            LOG("help info isn't exsit");
        
        break;
        
        case 'c':
            //cmd_cw2017_handler(str, len);
            cmd_code_handler(str, len);
        break;
        
        case 'l':
            cmd_lowpower_handler(str, len);
            cmd_led_handler(str, len);
        break;
        
        case 'r':
           // cmd_reset_handler(str, len);
        break;
        
        case 'u':
            cmd_usb_handler(str, len);
        break;
        
        case 'w':
            cmd_wakeup_handler(str, len);
        break;        
        
        default:
            
        break;
        
        
    }
    
    
    
    
}


#else   // BOARD_ERRCHK_ENABLE

void PCB_Init( uint8 task_id ) {};
uint16 PCB_ProcessEvent( uint8 task_id, uint16 events ) { return 0;}


#endif // BOARD_ERRCHK_ENABLE





